package com.sailor.util;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.ThreadMXBean;
import java.net.*;
import java.util.Enumeration;

public class EnvTools {
	/**
	 * 获取当前服务进程ID
	 *
	 * @return int 进程ID
	 */
	public static int getPID() {
		return PID;
	}

	/**
	 * 获取当前服务IP地址
	 *
	 * @return long ipv4 整型数字
	 */
	public static long getNumberLocalIPV4IP() {
		return LOCAL_IPV4_IP_LONG;
	}

	/**
	 * 获取当前服务IP地址
	 *
	 * @return String ipv4字符串
	 */
	public static String getLocalIPV4IP() {
		return LOCAL_IPV4_IP;
	}

	/**
	 * 获取当前服务运行环境类型
	 *
	 * @return {@link Runtime} 运行环境
	 */
	public static Runtime runtime() {
		return RUNTIME;
	}

  /** RUNTIME == Runtime.SEP */
  public static boolean isSep() {
    return RUNTIME == Runtime.SEP;
  }

  /** RUNTIME == Runtime.SIT */
  public static boolean isSit() {
    return RUNTIME == Runtime.SIT;
  }

  /** RUNTIME == Runtime.RC */
  public static boolean isRc() {
    return RUNTIME == Runtime.RC;
  }

  /** RUNTIME == Runtime.RELEASE */
  public static boolean isRelease() {
    return RUNTIME == Runtime.RELEASE;
  }

  /** RUNTIME == Runtime.PRODUCTION */
  public static boolean isProd() {
    return RUNTIME == Runtime.PRODUCTION;
  }

  /** RUNTIME == Runtime.DEV||RUNTIME == Runtime.SEP||RUNTIME == Runtime.SIT */
  public static boolean isTestCompatible() {
    return RUNTIME == Runtime.DEV || RUNTIME == Runtime.SEP || RUNTIME == Runtime.SIT;
  }

  /** RUNTIME == Runtime.RC||RUNTIME == Runtime.RELEASE||RUNTIME == Runtime.PRODUCTION */
  public static boolean isOnlineCompatible() {
    return RUNTIME == Runtime.RC || RUNTIME == Runtime.RELEASE || RUNTIME == Runtime.PRODUCTION;
  }

	/**
	 * 获取CPU使用率(0~100)
	 *
	 * @return int CPU使用率
	 */
	public synchronized static double load() {
		long total = 0L;
		long[] tids = THREAD_MX_BEAN.getAllThreadIds();
		for (long tid : tids) {
			total += THREAD_MX_BEAN.getThreadCpuTime(tid);
		}

		long current = System.nanoTime();
		long usedTime = total - lastUsedTime;
		long totalPassedTime = current - lastCheckedCpuTime;
		lastCheckedCpuTime = current;
		lastUsedTime = total;

		return (((double) usedTime) / totalPassedTime / OSMXB.getAvailableProcessors()) * 100;
	}

	/**
	 * 获取当前服务运行区域
	 *
	 * @return 运行区域
	 * @see IdcDefinition
	 */
	public static IdcDefinition getIdcDefinition() {return IDC_DEFINITION;}

	private static IdcDefinition _getIdcDefinition() {
		String regionDef = System.getProperty("sailor.region", System.getenv("CONTAINER_REGION"));
		return IdcDefinition.of(regionDef);
	}

	private static Runtime _getRuntime() {
		String env = System.getProperty("sailor.env", System.getenv("CONTAINER_ENV"));
		if (env == null) {
			env = "dev";
		}

		if (env.equalsIgnoreCase("prod") || env.equalsIgnoreCase("production")) {
			return Runtime.PRODUCTION;
		} else if (env.equalsIgnoreCase("staging")) {
			return Runtime.STAGING;
		} else if (env.equalsIgnoreCase("rc")) {
			return Runtime.RC;
		} else if (env.equalsIgnoreCase("release")) {
			return Runtime.RELEASE;
		} else if (env.equalsIgnoreCase("sep")) {
			return Runtime.SEP;
		} else if (env.equalsIgnoreCase("sit")) {
			return Runtime.SIT;
		} else {
			return Runtime.DEV;
		}
	}

	private static String _getServiceName(){
		return getPredefinedValue(SERVICE_KEY, "snowball");
	}

	private static int _getPID() {
		String name = ManagementFactory.getRuntimeMXBean().getName();
		int offset = -1;
		if (name == null || (offset = name.indexOf("@")) == -1) {
			return -1;
		} else {
			try {
				return Integer.parseInt(name.substring(0, offset));
			} catch (Throwable e) {
				return -1;
			}
		}
	}

	private static String _getLocalIPV4IP() {
		String ip = null;
		try {
			ip = getPredefinedValue(IP_KEY, "");
			if (ip.length() <= 0) {
				Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
				while (interfaces.hasMoreElements()) {
					NetworkInterface ni = interfaces.nextElement();
					if (ni.isLoopback()) {
						continue;
					}

					Enumeration<InetAddress> addresses = ni.getInetAddresses();
					while (addresses.hasMoreElements()) {
						InetAddress address = addresses.nextElement();
						if (address instanceof Inet4Address) {
							ip = address.getHostAddress();
							break;
						}
					}
				}
			}
		} catch (SocketException e) {
			LOGGER.warn("can't get network interfaces", e);
		}

		if (ip == null || (ip = ip.trim()).length() == 0) {
			try {
				ip = Inet4Address.getLocalHost().getHostAddress();
			} catch (UnknownHostException e) {
				LOGGER.warn("can't get localhost address", e);
			}
		}

		return ip == null ? "0.0.0.0" : ip;
	}

	private static long ip2Long(String ip) {
		String[] segs = StringUtils.split(ip, '.');
		long result = 0L;
		result |= Integer.parseInt(segs[0]) << 24;
		result |= Integer.parseInt(segs[1]) << 16;
		result |= Integer.parseInt(segs[2]) << 8;
		result |= Integer.parseInt(segs[3]);
		return result;
	}

	public static final String getPredefinedValue(String configKey, String defaultValue) {
		String value = System.getProperty(configKey);
		if (value == null) {
			value = System.getenv(configKey);
		}
		if (value == null) {
			value = defaultValue;
		}
		return value;
	}

	public static enum Runtime {
		PRODUCTION("prod"), STAGING("staging"), RC("rc"), RELEASE("release"), SEP("sep"), SIT("sit"), DEV("dev");

		Runtime(String name) {
			this.name = name;
		}

		@Override
		public String toString() {
			return name;
		}

		private final String name;
	}

	public static final String serviceName = _getServiceName();

	private static long lastCheckedCpuTime = System.nanoTime();
	private static long lastUsedTime = 0L;
	private static final String SERVICE_KEY = "sailor.service";
	public static final String IP_KEY = "sailor.ip";

	private static final Runtime RUNTIME = _getRuntime();
	private static final int PID = _getPID();
	private static final String LOCAL_IPV4_IP = _getLocalIPV4IP();
	private static final long LOCAL_IPV4_IP_LONG = ip2Long(LOCAL_IPV4_IP);
	private static final OperatingSystemMXBean OSMXB = ManagementFactory.getOperatingSystemMXBean();
	private static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean();
	private static final Logger LOGGER = LoggerFactory.getLogger(EnvTools.class);

	private static final IdcDefinition IDC_DEFINITION = _getIdcDefinition();
}
